/*
 * Copyright 2009-2010 the original author or authors.
 *
 * Licensed under the Apache license, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.internna.iwebjtracker.spring.mvc;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import org.internna.iwebmvc.crypto.Cipherer;
import org.internna.iwebmvc.dao.DAO;
import org.internna.iwebmvc.model.UUID;
import org.internna.iwebmvc.utils.Assert;
import org.internna.iwebmvc.crypto.Decipherer;
import org.internna.iwebmvc.model.rss.RSS;
import org.internna.iwebmvc.model.rss.RSSItem;
import org.internna.iwebmvc.utils.CollectionUtils;
import org.internna.iwebjtracker.model.Activity;
import org.internna.iwebjtracker.services.TrackerUserManager;
import org.springframework.ui.ModelMap;
import org.springframework.context.MessageSource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.web.bind.annotation.RequestMapping;

import static org.internna.iwebmvc.utils.StringUtils.hasText;

/**
 * Accepts requests to generate the RSS feeds for a project or issue.
 *
 * @author Jose Noheda
 * @since 1.0
 */
@Controller
@RequestMapping("/rss.iwebmvc")
public final class RSSController {

    /**
     * Key (JSP) to retrieved the RSS object
     */
    public static final String RSS_KEY = "rss";

    private DAO dao;
    private Cipherer cipherer;
    private List<Locale> locales;
    private Decipherer decipherer;
    private MessageSource messageResolver;
    private TrackerUserManager userManager;

    /**
     * Spring injection point (REQUIRED)
     *
     * @param dao a not null persistence facade
     */
    @Required public void setDao(DAO dao) {
        Assert.notNull(dao);
        this.dao = dao;
    }

    /**
     * Spring injection point (REQUIRED)
     *
     * @param decipherer a not null implementation
     */
    @Required public void setDecipherer(Decipherer decipherer) {
        Assert.notNull(decipherer);
        this.decipherer = decipherer;
    }

    /**
     * Spring injection point (REQUIRED)
     *
     * @param decipherer a not null implementation
     */
    @Required public void setCipherer(Cipherer cipherer) {
        Assert.notNull(cipherer);
        this.cipherer = cipherer;
    }

    /**
     * Spring injection point (REQUIRED)
     *
     * @param decipherer a not null implementation
     */
    @Required public void setLocales(List<Locale> locales) {
        this.locales = locales;
    }

    /**
     * Spring injection point (REQUIRED)
     *
     * @param decipherer a non null implementation
     */
    @Required public void setMessageResolver(MessageSource messageResolver) {
        Assert.notNull(messageResolver);
        this.messageResolver = messageResolver;
    }

    /**
     * Spring injection point (REQUIRED)
     *
     * @param userManager a non null instance
     */
    public void setUserManager(TrackerUserManager userManager) {
        Assert.notNull(userManager);
        this.userManager = userManager;
    }

    /**
     * Gets the project from its primary key and populates the model.
     *
     * @param uuid provided by the "project" URL parameter
     * @param model injected by Spring MVC automatically
     *
     * @return /project/index
     */
    @RequestMapping(method = RequestMethod.GET)
    public String rss(@RequestParam(value = "project", required = false) String project, @RequestParam(value = "issue", required = false) String issue, @RequestParam(value = "user", required = false) String user, ModelMap model) {
        List<Activity> activities = null;
        String path = null;
        if (hasText(issue)) {
            activities = generateIssueRSS(uuidFromEncryptedString(issue));
            if (CollectionUtils.isNotEmpty(activities)) {
                path = activities.get(0).getIssue().getAlias();
            }
        } else if (hasText(project)) {
            activities = generateProjectRSS(uuidFromEncryptedString(project));
            if (CollectionUtils.isNotEmpty(activities)) {
                path = activities.get(0).getProject().getAlias();
            }
        } else if (hasText(user)){
            activities = generateUserRSS(user);
        } else {
            activities = generateRSS();
        }
        fillModel(path, activities, model);
        return "/rss/index";
    }

    private UUID uuidFromEncryptedString(String uuid) {
        Assert.isEncrypted(decipherer, uuid);
        return new UUID(decipherer.decrypt(uuid));
    }

    /**
     * Generates the list of activities for the whole IWebJTracker instance.
     *
     * @return any
     */
    protected List<Activity> generateRSS() {
        return dao.findByNamedQuery(Activity.FIND_LAST_ACTIVITY, 0, RSS.FEED_SIZE, null);
    }

    /**
     * Generates the list of activities for a specific project.
     *
     * @param project a non null instance
     * @return any
     */
    protected List<Activity> generateProjectRSS(UUID project) {
        return generateActivities(Activity.FIND_LAST_ACTIVITY_FOR_PROJECT, "project", project);
    }

    /**
     * Generates the list of activities for a specific issue.
     *
     * @param issue a non null instance
     * @return any
     */
    protected List<Activity> generateIssueRSS(UUID issue) {
        return generateActivities(Activity.FIND_LAST_ACTIVITY_FOR_ISSUE, "issue", issue);
    }

    /**
     * Generates the list of activities for all the projects for a user.
     * @param user
     * @return
     */
    protected List<Activity> generateUserRSS(String user) {
        return generateActivities(Activity.FIND_LAST_ACTIVITY_FOR_USER, "user", userManager.getTrackerUser(user));
    }

    private List<Activity> generateActivities(String query, String key, Object value) {
        Map<String, Object> params = new HashMap<String, Object>(1);
        params.put(key, value);
        return dao.findByNamedQuery(query, 0, RSS.FEED_SIZE, params);
    }

    /**
     * Injects a RSS instance in the model created from the activities retrieved.
     *
     * @param activities any
     * @param model a non null instance
     */
    protected void fillModel(String path, List<Activity> activities, ModelMap model) {
        RSS rss = new RSS();
        rss.setUrl(path == null ? "/rss" : "/rss/" + path);
        rss.setTitle("IWebJTracker feeds");
        if (CollectionUtils.isNotEmpty(activities)) {
            for (Activity activity : activities) {
                RSSItem item = activity.toRSS(cipherer, locales, messageResolver);
                item.setLink(setUrl(activity));
                rss.addItem(item);
            }
        }
        model.addAttribute(RSS_KEY, rss);
    }

    /**
     * Gets the friendly URL for the activity.
     *
     * @param activity a non null instance
     * @return a non empty string
     */
    protected String setUrl(Activity activity) {
        return activity.getIssue() != null ? "/issue/" + activity.getIssue().getAlias() : "/project/" + activity.getProject().getAlias();
    }

}
